/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "stdafx.h"

#include "渲染节点.h"

#include <物体/物体.h>


#include <Context/当前默认操作数据.h>
#include <Context/节点数据操作.h>
#include "Context/数据创建销毁.h"
#include "节点编辑.h"

#include "节点/插座/字符插座.h"
#include "节点/插座/list/list物体插座.h"
#include "节点/插座/list/list数值插座.h"
#include "节点/插座/通用插座.h"
#include "节点/插座/材质纹理插座.h"
#include "节点/插座/C_物体插座.h"
#include "节点/插座/list/list矢量插座.h"

#include "节点/socket_utils.h"




static void on_设置路径更新节点(S_Props& prop) {
	E_对话框类型 类型 = E_对话框类型::e_写入;

	f_ui_set路径编辑框对话框类型(prop.m_UI->m_部件, 类型);
	f_ui_set路径编辑框对话框后缀(prop.m_UI->m_部件, ".png");
}




C_渲染器配置节点::C_渲染器配置节点(S_设备环境& ctx) : C_节点基类(DEF_渲染器配置节点) {
	m_Name = L"渲染器";
	m_Ctx = ctx;
	m_更新方式 = E_节点更新方式::e_节点更新_逐帧;

	C_插座基类* socket;
	DEF_创建物体插座_I(L"摄像机");
	DEF_创建材质插座_I(L"环境材质");

	DEF_创建纹理插座_O(L"图像", ctx);



	m_分辨率 = f_alloc_uVec2Prop(nullptr, L"分辨率", 0, 1000000);
	m_分辨率.m_私有 = true;
	m_光反弹 = f_alloc_UI32Prop(nullptr, L"光反弹", 0, 1000000);
	m_光反弹.m_私有 = true;
	m_光采样 = f_alloc_UI32Prop(nullptr, L"光采样", 0, 1000000);
	m_光采样.m_私有 = true;
	m_采样 = f_alloc_UI32Prop(nullptr, L"采样", 0, 1000000);
	m_采样.m_私有 = true;

	f_prop_uVec2(m_分辨率) = { 1920,1080 };
	f_prop_UI32(m_光反弹) = 8;
	f_prop_UI32(m_光采样) = 8;
	f_prop_UI32(m_采样) = 256;

	m_渲染纹理 = f_tex_创建帧缓存纹理(m_Ctx, { 1024, 1024, 1 }, E_纹理格式::e_tf_RGBA8U_U, E_纹理维度类型::e_2D);

	static S_纹理采样器* 默认采样器 = f_tex_创建纹理采样器(ctx);
	f_tex_安装纹理采样器(m_渲染纹理, 默认采样器);
}

C_渲染器配置节点::~C_渲染器配置节点() {
	f_prop_Release(m_分辨率);
	f_prop_Release(m_光反弹);
	f_prop_Release(m_采样);
}

bool C_渲染器配置节点::f_update() {
	auto* socket1 = f_get输入插座(1);
	auto* 摄像机 = DEF_物体插座数据(socket1, 0);
	if (摄像机 && 摄像机->m_Type != E_物体类型::t_摄像机) {
		摄像机 = f_ob_以类型查找子物体(摄像机, E_物体类型::t_摄像机);
	}

	auto scene = f_NodeCtx_get默认场景();
	S_材质* 材质 = DEF_材质插座数据(f_get输入插座(2), 0);
	if (材质 && 材质->m_Shader) {
		scene->m_光追后端->m_mapPtr_渲染帧数据->m_world_ShaderID = 材质->m_Shader->m_ShaderIndex;
	}
	else {
		scene->m_光追后端->m_mapPtr_渲染帧数据->m_world_ShaderID = -1;
	}


	switch (S_光追后端::g_渲染状态) {
	case E_离线渲染状态::e_光追渲染_单帧:
	case E_离线渲染状态::e_光追渲染_序列:
		break;
	default:
		return false;
		break;
	}

	if (摄像机) {
		auto 采样 = f_prop_UI32(m_采样);
		

		S_RayRenderAttr Attr;
		Attr.光采样 =  f_prop_UI32(m_光采样);
		Attr.反弹次数 = f_prop_UI32(m_光反弹);
		Attr.采样次数 = f_prop_UI32(m_采样);

		
		
		f_scene_设置光追渲染采样(scene, Attr);

		auto 分辨率 = f_prop_uVec2(m_分辨率);
		f_tex_修改大小(m_渲染纹理, { 分辨率.x, 分辨率.y, 1 });

		dynamic_cast<S_摄像机*>(摄像机)->m_分辨率 = { int32(分辨率.x), int32(分辨率.y) };
		m_渲染纹理->m_命令缓存 = scene->m_光追后端->m_渲染命令缓存;


		S_摄像机* camera = dynamic_cast<S_摄像机*>(摄像机);
		if (camera) {
			auto 帧 = f_NodeCtx_get帧();
			//f_NodeCtx_set场景当前时间(f_prop_I32(帧.当前帧));
			f_NodeCtx_set场景当前时间(S_节点数据::g_渲染帧编号);

			camera->f_set宽高比({ float32(分辨率.x), float32(分辨率.y) });
			scene->f_Update(camera);

			scene->m_光追后端->f_重置渲染帧记录();
			
			if (scene->mf_渲染前Update) {
				scene->mf_渲染前Update((S_结构对象指针)this);
			}

			scene->f_RayRender(camera, 分辨率, *m_渲染纹理, Attr.采样次数);
		}


		f_get输出插座(1)->f_setData(m_渲染纹理);
	}
	else {
		return true;
	}

	return false;
}

void C_渲染器配置节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_分辨率, f);
	f_prop_Load(m_光反弹, f);
	f_prop_Load(m_采样, f);
	
}

void C_渲染器配置节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_分辨率, f);
	f_prop_Save(m_光反弹, f);
	f_prop_Save(m_采样, f);
	
}

C_节点基类* f_node_创建渲染器配置节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_渲染器配置节点(ctx);
}

C_节点基类* f_node_加载渲染器配置节点(S_设备环境& ctx, FILE* f) {
	C_渲染器配置节点* node = new C_渲染器配置节点(ctx);
	return node;
}

void f_node_保存渲染器配置节点(C_节点基类* n, FILE* f) {
	C_渲染器配置节点* node = dynamic_cast<C_渲染器配置节点*>(n);
}





C_渲染输出节点::C_渲染输出节点(S_设备环境& ctx) : C_节点基类(DEF_渲染输出节点) {
	m_Name = L"渲染输出";
	m_Ctx = ctx;
	

	C_插座基类* socket;
	DEF_创建路径插座_I(L"路径");
	DEF_创建纹理插座_I(L"图像", ctx);

	m_相对路径 = f_alloc_BoolProp(nullptr, L"相对路径");
	m_颜色通道 = f_alloc_EnumProp(nullptr, { {L"R", ""}, {L"RGB", ""}, {L"RGBA", ""} }, L"通道");
	m_位深 = f_alloc_EnumProp(nullptr, { {L"8", ""}, {L"16", ""}, {L"32", ""} }, L"位深");
	m_格式 = f_alloc_EnumProp(nullptr, { {L"png", ""}, {L"jpg", ""}, {L"exr", ""} }, L"通道");


	DEF_路径插座(f_get输入插座(1))->m_Value.m_UI->m_Update = on_设置路径更新节点;

	auto& path = *DEF_路径插座数据(f_get输入插座(1), 0);
	path = std::filesystem::temp_directory_path().string();
	//path = f_String转码(std::filesystem::temp_directory_path().string(), "utf-8");
	
}

C_渲染输出节点::~C_渲染输出节点(){
	f_prop_Release(m_相对路径);
	f_prop_Release(m_颜色通道);
	f_prop_Release(m_位深);
	f_prop_Release(m_格式);
}

bool C_渲染输出节点::f_update() {
	auto& path = *DEF_路径插座数据(f_get输入插座(1), 0);
	auto* 纹理 = DEF_纹理插座数据(f_get输入插座(2), 0);

	if (!纹理 || !(纹理->m_Size.x) || !(纹理->m_Size.y) || !(纹理->m_Size.z)) return false;

	std::string 拼接路径 = f_nodeCtx_相对路径补全(path.string());
	f_file_创建目录(拼接路径);

	switch (S_光追后端::g_渲染状态) {
	case E_离线渲染状态::e_光追渲染_单帧:
		f_tex_保存到文件(纹理, path.string());
		std::cout << "保持图像:" << path << std::endl;
		break;

	case E_离线渲染状态::e_光追渲染_序列: {
		auto 文件路径 = f_file_get路径(拼接路径);
		auto 无后缀文件名 = f_file_取无后缀文件名(拼接路径);

		文件路径 += 无后缀文件名 + "_" + f_整数值转字符串(S_节点数据::g_渲染帧编号) + ".png";
		f_tex_保存到文件(纹理, 文件路径);
		std::cout<<"保持图像:"<< 文件路径 << std::endl;
		break;
	}
	}
	
	return false;
}

void C_渲染输出节点::f_读取(FILE* f) {
	C_节点基类::f_读取(f);
	f_prop_Load(m_相对路径, f);
	f_prop_Load(m_颜色通道, f);
	f_prop_Load(m_位深, f);
	f_prop_Load(m_格式, f);
}

void C_渲染输出节点::f_写入(FILE* f) {
	C_节点基类::f_写入(f);
	f_prop_Save(m_相对路径, f);
	f_prop_Save(m_颜色通道, f);
	f_prop_Save(m_位深, f);
	f_prop_Save(m_格式, f);
}

C_节点基类* f_node_创建渲染输出节点(S_设备环境& ctx, C_节点树* 子节点树) {
	return new C_渲染输出节点(ctx);
}

C_节点基类* f_node_加载渲染输出节点(S_设备环境& ctx, FILE* f) {
	C_渲染输出节点* node = new C_渲染输出节点(ctx);

	return node;
}

void f_node_保存渲染输出节点(C_节点基类* n, FILE* f) {
	C_渲染输出节点* node = dynamic_cast<C_渲染输出节点*>(n);
}






